#!/bin/bash

#-----------------------------------------------------------------------
# 一个用于通过 openjdk:8 镜像交互式部署自定义 .jar 应用程序的脚本。
# 功能:
# 1. 检查 Docker 是否已安装，如果未安装则会提示并尝试自动安装。
# 2. 允许用户指定 .jar 文件的路径。
# 3. 允许用户指定可选的 application.properties 配置文件路径。
# 4. 允许用户指定可选的 startup.sh 启动脚本。
# 5. 允许用户自定义容器名称、主机端口和应用在容器内的端口。
# 6. 允许用户指定容器的工作目录。
# 7. 自动在当前目录下创建并挂载数据卷，用于持久化存储。
# 8. 自动拉取 openjdk:8 镜像并启动容器运行 .jar 文件。
# 9. 指定目录中执行：bash <(curl -s -L https://gitee.com/securitypass/auto-scirpt/raw/master/linux/docker/start_java_app.sh)
#-----------------------------------------------------------------------

# 设置颜色变量，用于美化输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # 无颜色

# --- 安装 Docker (Debian/Ubuntu) ---
install_docker_debian() {
    echo -e "${YELLOW}正在为 Debian/Ubuntu 系统安装 Docker... 这可能需要几分钟。${NC}"
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install -y docker-ce docker-ce-cli containerd.io
    sudo systemctl start docker
    sudo systemctl enable docker
    echo -e "${GREEN}Docker 安装完成并已启动。${NC}"
    if ! command -v docker &> /dev/null; then
        echo -e "${RED}Docker 安装后仍然找不到命令, 请检查安装过程中的错误。${NC}"
        exit 1
    fi
}

# --- 安装 Docker (CentOS/RHEL/Fedora) ---
install_docker_centos() {
    echo -e "${YELLOW}正在为 CentOS/RHEL/Fedora 系统安装 Docker... 这可能需要几分钟。${NC}"
    sudo yum install -y yum-utils
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    sudo yum install -y docker-ce docker-ce-cli containerd.io
    sudo systemctl start docker
    sudo systemctl enable docker
    echo -e "${GREEN}Docker 安装完成并已启动。${NC}"
    if ! command -v docker &> /dev/null; then
        echo -e "${RED}Docker 安装后仍然找不到命令, 请检查安装过程中的错误。${NC}"
        exit 1
    fi
}


# --- 1. 检查 Docker 环境 ---
check_docker() {
    echo "正在检查 Docker 环境..."
    if ! command -v docker &> /dev/null; then
        echo -e "${RED}错误: 未检测到 Docker 命令。${NC}"
        read -p "是否尝试自动安装 Docker? (y/n): " install_choice
        if [[ "$install_choice" == "y" || "$install_choice" == "Y" ]]; then
            if [ -f /etc/os-release ]; then
                . /etc/os-release
                if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
                    install_docker_debian
                elif [[ "$ID" == "centos" || "$ID" == "rhel" || "$ID" == "fedora" ]]; then
                    install_docker_centos
                else
                    echo -e "${YELLOW}抱歉, 暂不支持您的 Linux 发行版 (${ID}) 的自动安装。${NC}"
                    echo "请参考官方文档手动安装: https://docs.docker.com/engine/install/"
                    exit 1
                fi
            else
                echo -e "${YELLOW}无法确定 Linux 发行版, 无法自动安装。${NC}"
                echo "请参考官方文档手动安装: https://docs.docker.com/engine/install/"
                exit 1
            fi
        else
            echo "用户取消安装。脚本退出。"
            exit 1
        fi
    fi

    if ! docker info &> /dev/null; then
        echo -e "${RED}错误: Docker 服务未运行。${NC}"
        echo "请尝试使用 'sudo systemctl start docker' 启动服务后再运行此脚本。"
        exit 1
    fi
    echo -e "${GREEN}Docker 环境正常。${NC}"
    echo "----------------------------------------"
}

# --- 2. 获取用户输入 ---
get_user_input() {
    # 获取 .jar 文件路径
    read -p "请输入你的 .jar 文件的完整路径 (例如: /home/user/app.jar): " JAR_PATH
    if [ ! -f "$JAR_PATH" ]; then
        echo -e "${RED}错误: 文件不存在于 '${JAR_PATH}'。请检查路径。${NC}"
        exit 1
    fi

    # (可选) 获取 application.properties 路径
    read -p "请输入 application.properties 的可选路径 (留空则跳过): " PROPERTIES_PATH
    if [ -n "$PROPERTIES_PATH" ] && [ ! -f "$PROPERTIES_PATH" ]; then
        echo -e "${RED}错误: 配置文件不存在于 '${PROPERTIES_PATH}'。请检查路径。${NC}"
        exit 1
    fi

    # (可选) 获取 startup.sh 路径
    read -p "请输入 startup.sh 的可选路径 (留空则跳过): " STARTUP_SCRIPT_PATH
    if [ -n "$STARTUP_SCRIPT_PATH" ] && [ ! -f "$STARTUP_SCRIPT_PATH" ]; then
        echo -e "${RED}错误: 启动脚本不存在于 '${STARTUP_SCRIPT_PATH}'。请检查路径。${NC}"
        exit 1
    fi

    # 获取容器名称
    read -p "请输入容器的名称 (例如: my-java-app): " CONTAINER_NAME
    if [ -z "$CONTAINER_NAME" ]; then
        echo -e "${RED}错误: 容器名称不能为空。脚本退出。${NC}"
        exit 1
    fi

    # 获取应用在容器内的端口
    read -p "请输入你的Java应用在容器内监听的端口 (例如: 8080): " APP_PORT
    if ! [[ "$APP_PORT" =~ ^[0-9]+$ ]] || [ "$APP_PORT" -lt 1 ] || [ "$APP_PORT" -gt 65535 ]; then
        echo -e "${RED}错误: 无效的应用端口。请输入1-65535之间的数字。脚本退出。${NC}"
        exit 1
    fi

    # 获取要映射到主机上的端口
    read -p "请输入要映射到主机上的端口 (例如: 8080): " HOST_PORT
    if ! [[ "$HOST_PORT" =~ ^[0-9]+$ ]] || [ "$HOST_PORT" -lt 1 ] || [ "$HOST_PORT" -gt 65535 ]; then
        echo -e "${YELLOW}输入无效, 将使用与应用端口相同的端口 ${APP_PORT}。${NC}"
        HOST_PORT=${APP_PORT}
    fi

    # (可选) 获取容器工作目录
    read -p "请输入容器的工作目录 (留空则使用默认): " WORK_DIR

    # 选择 OpenJDK 版本
    echo "请选择 openjdk 镜像版本:"
    echo "1) cimg/openjdk:8.0.462"
    echo "2) cimg/openjdk:21.0.8"
    echo "3) cimg/openjdk:17.0.16"
    echo "4) cimg/openjdk:11.0.28"
    read -p "请输入序号 (1-4): " IMAGE_CHOICE
    case "$IMAGE_CHOICE" in
        1) IMAGE_NAME="1.abclist.eu.org/cimg/openjdk:8.0.462" ;;
        2) IMAGE_NAME="1.abclist.eu.org/cimg/openjdk:21.0.8" ;;
        3) IMAGE_NAME="1.abclist.eu.org/cimg/openjdk:17.0.16" ;;
        4) IMAGE_NAME="1.abclist.eu.org/cimg/openjdk:11.0.28" ;;
        *) echo -e "${RED}无效选择，脚本退出。${NC}"; exit 1 ;;
    esac

    echo "----------------------------------------"
}

# --- 3. 准备本地目录 ---
prepare_directory() {
    DATA_DIR="$(pwd)/app_data"

    echo -e "${YELLOW}将在当前目录下创建并挂载以下数据卷:${NC}"
    echo " - 主机路径: ${DATA_DIR}"
    echo " - 容器路径: /data"
    echo "此目录将用于应用的数据持久化。"

    mkdir -p ${DATA_DIR}
    echo "本地数据目录已准备就绪。"
    echo "----------------------------------------"
}

# --- 4. 启动容器 ---
start_container() {
    echo -e "${YELLOW}准备启动 Java 应用容器...${NC}"

    # 检查同名容器是否已存在
    if [ $(docker ps -a -f name=^/${CONTAINER_NAME}$ | grep -w ${CONTAINER_NAME} | wc -l) -gt 0 ]; then
        echo "发现已存在的同名容器 '${CONTAINER_NAME}'，正在停止并删除..."
        docker stop ${CONTAINER_NAME} > /dev/null
        docker rm ${CONTAINER_NAME} > /dev/null
        echo "旧容器 '${CONTAINER_NAME}' 已被删除。"
    fi
    
    # 拉取镜像
    echo "正在拉取镜像: ${IMAGE_NAME}..."
    docker pull 1.abclist.eu.org/library/${IMAGE_NAME}
    if [ $? -ne 0 ]; then
        echo -e "${RED}✘ 镜像拉取失败! 请检查网络或镜像名称。${NC}"
        exit 1
    fi
    echo -e "${GREEN}镜像拉取成功。${NC}"
    echo "----------------------------------------"

    # 准备 docker run 命令的参数
    DOCKER_RUN_ARGS=(
        -d
        --name "$CONTAINER_NAME"
        -e LANG=zh_CN.UTF-8
        -e LANGUAGE=zh_CN:zh
        -p "${HOST_PORT}:${APP_PORT}"
        -v "${JAR_PATH}:/app.jar"
        -v "${DATA_DIR}:/data"
    )
    
    # 如果用户指定了工作目录, 则添加到参数中
    if [ -n "$WORK_DIR" ]; then
        DOCKER_RUN_ARGS+=(-w "$WORK_DIR")
    fi

    # 如果用户提供了配置文件, 则添加挂载
    if [ -n "$PROPERTIES_PATH" ]; then
        echo "正在挂载配置文件: ${PROPERTIES_PATH}"
        DOCKER_RUN_ARGS+=(-v "${PROPERTIES_PATH}:/config/application.properties")
    fi

    # 准备容器的启动命令
    local CONTAINER_COMMAND
    if [ -n "$STARTUP_SCRIPT_PATH" ]; then
        echo "使用自定义启动脚本: ${STARTUP_SCRIPT_PATH}"
        DOCKER_RUN_ARGS+=(-v "${STARTUP_SCRIPT_PATH}:/startup.sh")
        # 确保脚本有执行权限
        chmod +x "$STARTUP_SCRIPT_PATH"
        CONTAINER_COMMAND=( "sh" "/startup.sh" )
    else
        local JAVA_CMD="java -jar /app.jar"
        # 如果提供了配置文件且未使用自定义启动脚本, 则自动添加 spring boot 参数
        if [ -n "$PROPERTIES_PATH" ]; then
            JAVA_CMD+=" --spring.config.location=file:/config/application.properties"
        fi
        CONTAINER_COMMAND=( "sh" "-c" "$JAVA_CMD" )
    fi

    # 运行容器
    echo "正在以名称 '${CONTAINER_NAME}' 启动容器..."
    docker run "${DOCKER_RUN_ARGS[@]}" "${IMAGE_NAME}" "${CONTAINER_COMMAND[@]}"

    # 检查容器是否成功运行
    sleep 5 # 等待几秒钟让容器有时间启动
    if [ $(docker ps -f name=^/${CONTAINER_NAME}$ | grep -w ${CONTAINER_NAME} | wc -l) -gt 0 ]; then
        echo -e "${GREEN}✔ Java 应用部署成功!${NC}"
        echo -e "  - ${YELLOW}容器名称:${NC} ${CONTAINER_NAME}"
        echo -e "  - ${YELLOW}访问地址:${NC} http://localhost:${HOST_PORT}"
        echo -e "  - ${YELLOW}数据存储路径:${NC} ${DATA_DIR}"
        echo -e "  - ${YELLOW}查看日志:${NC} docker logs -f ${CONTAINER_NAME}"
    else
        echo -e "${RED}✘ 部署失败! 请通过 'docker logs ${CONTAINER_NAME}' 查看错误日志。${NC}"
    fi

    echo "----------------------------------------"
}

# --- 主执行流程 ---
main() {
    check_docker
    get_user_input
    prepare_directory
    start_container
}

# 调用主函数
main
